from wheels.pi.coro._TaskDescriptor import TaskDescriptor



class TaskScheduler(object):

    def __init__(self, task_processor):
        self._task_count = 0
        self._task_table = {}
        self._wait_table = {}
        self._ready_queue = []
        self._task_processor = task_processor


    def create_task(self, coro, parent_tid):
        self._task_count += 1
        td = TaskDescriptor(self._task_count, parent_tid, coro)
        self._task_table[td.tid] = td
        return td.tid


    def schedule_task(self, tid, val=None, err=None):
        self._ready_queue.append((tid, val, err))


    def terminate_task(self, tid, status=None, killed=False):
        try:
            for tid_ in self._wait_table[tid]:
                self.schedule_task(tid_, val=(tid, status, killed))
            del self._wait_table[tid]
        except:
            pass
        try:
            del self._task_table[tid]
        except:
            raise CoroError("no such task")


    def task_tid(self, tid):
        self.schedule_task(tid, val=tid)


    def task_cmd(self, tid):
        td = self._task_table[tid]
        self.schedule_task(tid, val=td.cmd)


    def task_pid(self, tid):
        td = self._task_table[tid]
        self.schedule_task(tid, val=td.parent_tid)


    def task_kill(self, tid, target_tid):
        try:
            self.terminate_task(target_tid, killed=True)
            self.schedule_task(tid)
        except CoroException, e:
            self.schedule_task(tid, err=e)


    def task_fork(self, tid, coro):
        child_tid = self.create_task(coro, tid)
        self.schedule_task(child_tid)
        self.schedule_task(tid, val=child_tid)


    def task_wait(self, tid, target_tid):
        if not target_tid in self._task_table:
            self.schedule_task(tid, err=CoroError("no such task"))
        if not target_tid in self._wait_table:
            self._wait_table[target_tid] = []
        self._wait_table[target_tid].append(tid)


    def task_exit(self, tid, status):
        self.terminate_task(tid, status)


    def run(self):
        while self._ready_queue:
            tid, send, throw = self._ready_queue.pop(0)
            td = self._task_table[tid]
            self._task_processor.run_task(td, send, throw)
